package com.leslie.common.utils.qrCode;


import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.qrcode.QrCodeUtil;
import cn.hutool.extra.qrcode.QrConfig;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;

import java.awt.*;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;

/**
 * 二维码工具类
 *
 * @author Leslie Lee
 * @TIME 1956/09/12
 * @Version 2003/04/01
 */
@Slf4j
public class QRCodeUtils {

    /**
     * 生成二维码到文件，【默认】宽、高均为：300像素
     *
     * @param content  二维码内容【文字或页面路径】
     * @param filePath 文件路径【"D:\\cs.jpg"】
     */
    public static void generateQRCode(String content, String filePath) {
        QrCodeUtil.generate(content, 300, 300, FileUtil.file(filePath));
    }

    /**
     * 浏览器直接下载，【默认】宽、高均为：300像素
     *
     * @param response response
     * @param content  二维码内容【文字或页面路径】
     * @param fileName 生成的文件名【"不带文件类型后缀"，例：.jpg、.png等】
     * @param isSuffix 传入的文件名是否带后缀【true】生成对应的后缀文件【false】默认png文件
     */
    public static void generateQRCode(HttpServletResponse response, String content, String fileName, Boolean isSuffix) throws IOException {
        OutputStream servletOutputStream = getServletOutputStream(response, fileName, isSuffix);
        if (isSuffix) {// 带后缀
            String suffix = StrUtil.subAfter(fileName, ".", true);
            QrCodeUtil.generate(content, 300, 300, suffix, servletOutputStream);
        } else {// 不带后缀，默认png
            QrCodeUtil.generate(content, 300, 300, "png", servletOutputStream);
        }
    }

    /**
     * 生成二维码到文件，自定义宽、高
     *
     * @param content  二维码内容【文字或页面路径】
     * @param width    宽
     * @param height   高
     * @param filePath 文件路径【"D:\\cs.jpg"】
     */
    public static void generateQRCode(String content, int width, int height, String filePath) {
        QrCodeUtil.generate(content, width, height, FileUtil.file(filePath));
    }

    /**
     * 浏览器直接下载，自定义宽、高
     *
     * @param response response
     * @param content  二维码内容【文字或页面路径】
     * @param width    宽
     * @param height   高
     * @param fileName 生成的文件名【"不带文件类型后缀"，例：.jpg、.png等】
     * @param isSuffix 传入的文件名是否带后缀【true】生成对应的后缀文件【false】默认png文件
     */
    public static void generateQRCode(HttpServletResponse response, String content, int width, int height, String fileName, Boolean isSuffix) throws IOException {
        OutputStream servletOutputStream = getServletOutputStream(response, fileName, isSuffix);
        if (isSuffix) {// 带后缀
            String suffix = StrUtil.subAfter(fileName, ".", true);
            QrCodeUtil.generate(content, width, height, suffix, servletOutputStream);
        } else {// 不带后缀，默认png
            QrCodeUtil.generate(content, width, height, "png", servletOutputStream);
        }
    }

    /**
     * 生成二维码到文件，【true】宽、高均为：300像素、二维码与背景边距：3、二维码颜色：青色、背景色：白色
     * 【false】宽、高均为：300像素
     *
     * @param content  二维码内容【文字或页面路径】
     * @param filePath 文件路径【"D:\\cs.jpg"】
     */
    public static void generateQRCodeColor(String content, String filePath, Boolean isColor) {
        if (isColor) {
            QrConfig config = getQrConfig(300, 300, 3, Color.CYAN, Color.WHITE, null, ErrorCorrectionLevel.M);
            QrCodeUtil.generate(content, config, FileUtil.file(filePath));
        } else {
            QrCodeUtil.generate(content, 300, 300, FileUtil.file(filePath));
        }
    }

    /**
     * 浏览器直接下载，【】宽、高均为：300像素、二维码与背景边距：3、二维码颜色：青色、背景色：白色
     *
     * @param response response
     * @param content  二维码内容【文字或页面路径】
     * @param fileName 生成的文件名【"不带文件类型后缀"，例：.jpg、.png等】
     * @param isSuffix 传入的文件名是否带后缀【true】生成对应的后缀文件【false】默认png文件
     */
    public static void generateQRCodeColor(HttpServletResponse response, String content, String fileName, Boolean isSuffix) throws IOException {
        OutputStream servletOutputStream = getServletOutputStream(response, fileName, isSuffix);
        QrConfig config = getQrConfig(300, 300, 3, Color.CYAN, Color.WHITE, null, ErrorCorrectionLevel.M);
        if (isSuffix) {
            String suffix = StrUtil.subAfter(fileName, ".", true);
            QrCodeUtil.generate(content, config, suffix, servletOutputStream);
        } else {
            QrCodeUtil.generate(content, config, "png", servletOutputStream);
        }
    }

    /**
     * 生成二维码到文件，【默认】宽、高均为：300像素、二维码与背景边距：3
     *
     * @param content   二维码内容【文字或页面路径】
     * @param foreColor 二维码颜色【青色：Color.CYAN】
     * @param backColor 背景色【白色：Color.WHITE】
     * @param filePath  文件路径【"D:\\cs.jpg"】
     */
    public static void generateQRCode(String content, Color foreColor, Color backColor, String filePath) {
        QrConfig config = getQrConfig(300, 300, 3, foreColor, backColor, null, ErrorCorrectionLevel.M);
        QrCodeUtil.generate(content, config, FileUtil.file(filePath));
    }

    /**
     * 浏览器直接下载，【默认】宽、高均为：300像素、二维码与背景边距：3
     *
     * @param response  response
     * @param content   二维码内容【文字或页面路径】
     * @param foreColor 二维码颜色【青色：Color.CYAN】
     * @param backColor 背景色【白色：Color.WHITE】
     * @param fileName  生成的文件名【"不带文件类型后缀"，例：.jpg、.png等】
     * @param isSuffix  传入的文件名是否带后缀【true】生成对应的后缀文件【false】默认png文件
     */
    public static void generateQRCode(HttpServletResponse response, String content, Color foreColor, Color backColor, String fileName, Boolean isSuffix) throws IOException {
        OutputStream servletOutputStream = getServletOutputStream(response, fileName, isSuffix);
        QrConfig config = getQrConfig(300, 300, 0, foreColor, backColor, null, ErrorCorrectionLevel.M);
        if (isSuffix) {
            String suffix = StrUtil.subAfter(fileName, ".", true);
            QrCodeUtil.generate(content, config, suffix, servletOutputStream);
        }
        QrCodeUtil.generate(content, config, "png", servletOutputStream);
    }

    /**
     * 生成二维码到文件，【默认】宽、高均为：300像素
     *
     * @param content   二维码内容【文字或页面路径】
     * @param margin    二维码与背景的边距
     * @param foreColor 二维码颜色【青色：Color.CYAN】
     * @param backColor 背景色【白色：Color.WHITE】
     * @param filePath  文件路径【"D:\\cs.jpg"】
     */
    public static void generateQRCode(String content, int margin, Color foreColor, Color backColor, String filePath) {
        QrConfig config = getQrConfig(300, 300, margin, foreColor, backColor, null, ErrorCorrectionLevel.M);
        QrCodeUtil.generate(content, config, FileUtil.file(filePath));
    }

    /**
     * 浏览器直接下载，【默认】宽、高均为：300像素
     *
     * @param response  response
     * @param content   二维码内容【文字或页面路径】
     * @param margin    二维码与背景的边距
     * @param foreColor 二维码颜色【青色：Color.CYAN】
     * @param backColor 背景色【白色：Color.WHITE】
     * @param fileName  生成的文件名【"不带文件类型后缀"，例：.jpg、.png等】
     * @param isSuffix  传入的文件名是否带后缀【true】生成对应的后缀文件【false】默认png文件
     */
    public static void generateQRCode(HttpServletResponse response, String content, int margin, Color foreColor, Color backColor, String fileName, Boolean isSuffix) throws IOException {
        OutputStream servletOutputStream = getServletOutputStream(response, fileName, isSuffix);
        QrConfig config = getQrConfig(300, 300, margin, foreColor, backColor, null, ErrorCorrectionLevel.M);
        if (isSuffix) {
            String suffix = StrUtil.subAfter(fileName, ".", true);
            QrCodeUtil.generate(content, config, suffix, servletOutputStream);
        } else {
            QrCodeUtil.generate(content, config, "png", servletOutputStream);
        }
    }

    /**
     * 生成二维码到文件
     *
     * @param content   二维码内容【文字或页面路径】
     * @param width     二维码的宽
     * @param height    二维码的高
     * @param margin    二维码与背景的边距
     * @param foreColor 二维码颜色【青色：Color.CYAN】
     * @param backColor 背景色【灰色：Color.WHITE】
     * @param filePath  文件路径【"D:\\cs.jpg"】
     */
    public static void generateQRCode(String content, int width, int height, int margin, Color foreColor, Color backColor, String filePath) {
        QrConfig config = getQrConfig(width, height, margin, foreColor, backColor, null, ErrorCorrectionLevel.M);
        QrCodeUtil.generate(content, config, FileUtil.file(filePath));
    }

    /**
     * 浏览器直接下载
     *
     * @param response  response
     * @param content   二维码内容【文字或页面路径】
     * @param width     二维码的宽
     * @param height    二维码的高
     * @param margin    二维码与背景的边距
     * @param foreColor 二维码颜色【青色：Color.CYAN】
     * @param backColor 背景色【灰色：Color.WHITE】
     * @param fileName  生成的文件名【"不带文件类型后缀"，例：.jpg、.png等】
     * @param isSuffix  传入的文件名是否带后缀【true】生成对应的后缀文件【false】默认png文件
     */
    public static void generateQRCode(HttpServletResponse response, String content, int width, int height, int margin, Color foreColor, Color backColor, String fileName, Boolean isSuffix) throws IOException {
        OutputStream servletOutputStream = getServletOutputStream(response, fileName, isSuffix);
        QrConfig config = getQrConfig(width, height, margin, foreColor, backColor, null, ErrorCorrectionLevel.M);
        if (isSuffix) {
            String suffix = StrUtil.subAfter(fileName, ".", true);
            QrCodeUtil.generate(content, config, suffix, servletOutputStream);
        } else {
            QrCodeUtil.generate(content, config, "png", servletOutputStream);
        }
    }

    /**
     * 生成二维码到文件
     *
     * @param content   二维码内容【文字或页面路径】
     * @param width     二维码的宽
     * @param height    二维码的高
     * @param margin    二维码与背景的边距
     * @param foreColor 二维码颜色【青色：Color.CYAN】
     * @param backColor 背景色【灰色：Color.WHITE】
     * @param imgPath   logo路径【"D:\\logo.png"】
     * @param filePath  文件路径【"D:\\cs.jpg"】
     */
    public static void generateQRCode(String content, int width, int height, int margin, Color foreColor, Color backColor, String imgPath, String filePath) {
        QrConfig config = getQrConfig(width, height, margin, foreColor, backColor, imgPath, ErrorCorrectionLevel.M);
        QrCodeUtil.generate(content, config, FileUtil.file(filePath));
    }

    /**
     * 浏览器直接下载
     *
     * @param response  response
     * @param content   二维码内容【文字或页面路径】
     * @param width     二维码的宽
     * @param height    二维码的高
     * @param margin    二维码与背景的边距
     * @param foreColor 二维码颜色【青色：Color.CYAN】
     * @param backColor 背景色【灰色：Color.WHITE】
     * @param imgPath   logo路径【"D:\\logo.png"】
     * @param fileName  生成的文件名【"不带文件类型后缀"，例：.jpg、.png等】
     * @param isSuffix  传入的文件名是否带后缀【true】生成对应的后缀文件【false】默认png文件
     */
    public static void generateQRCode(HttpServletResponse response, String content, int width, int height, int margin, Color foreColor, Color backColor, String imgPath, String fileName, Boolean isSuffix) throws IOException {
        OutputStream servletOutputStream = getServletOutputStream(response, fileName, isSuffix);
        QrConfig config = getQrConfig(width, height, margin, foreColor, backColor, imgPath, ErrorCorrectionLevel.M);
        if (isSuffix) {
            String suffix = StrUtil.subAfter(fileName, ".", true);
            QrCodeUtil.generate(content, config, suffix, servletOutputStream);
        } else {
            QrCodeUtil.generate(content, config, "png", servletOutputStream);
        }
    }

    /**
     * 生成二维码到文件
     *
     * @param content              二维码内容【文字或页面路径】
     * @param width                二维码的宽
     * @param height               二维码的高
     * @param margin               二维码与背景的边距
     * @param foreColor            二维码颜色【青色：Color.CYAN】
     * @param backColor            背景色【灰色：Color.WHITE】
     * @param imgPath              logo路径【"D:\\logo.png"】
     * @param errorCorrectionLevel 纠错级别【包括：L、M、Q、H几个参数，由低到高。低级别像素块大，可远距离识别，但遮挡就会造成无法识别。高级别则相反，像素块小，允许遮挡一定范围，但像素块更密集。】
     * @param filePath             文件路径【"D:\\cs.jpg"】
     */
    public static void generateQRCode(String content, int width, int height, int margin, Color foreColor, Color backColor, String imgPath, ErrorCorrectionLevel errorCorrectionLevel, String filePath) {
        QrConfig config = getQrConfig(width, height, margin, foreColor, backColor, imgPath, errorCorrectionLevel);
        QrCodeUtil.generate(content, config, FileUtil.file(filePath));
    }

    /**
     * 浏览器直接下载
     *
     * @param response             response
     * @param content              二维码内容【文字或页面路径】
     * @param width                二维码的宽
     * @param height               二维码的高
     * @param margin               二维码与背景的边距
     * @param foreColor            二维码颜色【青色：Color.CYAN】
     * @param backColor            背景色【灰色：Color.WHITE】
     * @param imgPath              logo路径【"D:\\logo.png"】
     * @param errorCorrectionLevel 纠错级别【包括：L、M、Q、H几个参数，由低到高。低级别像素块大，可远距离识别，但遮挡就会造成无法识别。高级别则相反，像素块小，允许遮挡一定范围，但像素块更密集。】
     * @param fileName             生成的文件名【"不带文件类型后缀"，例：.jpg、.png等】
     * @param isSuffix             传入的文件名是否带后缀【true】生成对应的后缀文件【false】默认png文件
     */
    public static void generateQRCode(HttpServletResponse response, String content, int width, int height, int margin, Color foreColor, Color backColor, String imgPath, ErrorCorrectionLevel errorCorrectionLevel, String fileName, Boolean isSuffix) throws IOException {
        OutputStream servletOutputStream = getServletOutputStream(response, fileName, isSuffix);
        QrConfig config = getQrConfig(width, height, margin, foreColor, backColor, imgPath, errorCorrectionLevel);
        if (isSuffix) {
            String suffix = StrUtil.subAfter(fileName, ".", true);
            QrCodeUtil.generate(content, config, suffix, servletOutputStream);
        } else {
            QrCodeUtil.generate(content, config, "png", servletOutputStream);
        }
    }

    /**
     * 浏览器直接下载
     *
     * @param content              二维码内容【文字或页面路径】
     * @param width                二维码的宽
     * @param height               二维码的高
     * @param margin               二维码与背景的边距
     * @param foreColor            二维码颜色【青色：Color.CYAN】
     * @param backColor            背景色【灰色：Color.WHITE】
     * @param imgPath              logo路径【"D:\\logo.png"】
     * @param errorCorrectionLevel 纠错级别【包括：L、M、Q、H几个参数，由低到高。低级别像素块大，可远距离识别，但遮挡就会造成无法识别。高级别则相反，像素块小，允许遮挡一定范围，但像素块更密集。】
     * @param svgOrAsciiArt        生成的二维码类型【AsciiArt、Svg，例：svg、asciiart、ascii、art、ascii art】
     * @param password             用于区别
     */
    public static String generateQRCode(String content, int width, int height, int margin, Color foreColor, Color backColor, String imgPath, ErrorCorrectionLevel errorCorrectionLevel, String svgOrAsciiArt, String password) {
        if (StrUtil.isBlank(password) || !password.equalsIgnoreCase("Leslie"))
            return "Leslie";
        QrConfig config = getQrConfig(width, height, margin, foreColor, backColor, imgPath, errorCorrectionLevel);
        if (!StrUtil.isBlank(svgOrAsciiArt)) {
            String lowerCase = svgOrAsciiArt.toLowerCase();
            if (lowerCase.equalsIgnoreCase("svg")) {
                return QrCodeUtil.generateAsSvg(content, config);
            } else if (lowerCase.equalsIgnoreCase("asciiart") ||
                    lowerCase.equalsIgnoreCase("ascii") ||
                    lowerCase.equalsIgnoreCase("art") ||
                    lowerCase.equalsIgnoreCase("ascii art")
            ) {
                return QrCodeUtil.generateAsAsciiArt(content, config);
            }
        }
        return "Leslie";
    }


    /**
     * 设置导出文件名及编码
     *
     * @param response response
     * @param fileName 文件名
     * @return ServletOutputStream
     * @throws IOException 异常信息
     */
    private static OutputStream getServletOutputStream(HttpServletResponse response, String fileName, Boolean isSuffix) throws IOException {
        response.setContentType("image/png");
//        response.setContentType("application/octet-stream");
        response.setCharacterEncoding("utf-8");
        String newFileName;
        if (isSuffix) {
            newFileName = URLEncoder.encode(fileName, StandardCharsets.UTF_8).replaceAll("\\+", "%20");
            response.setHeader("Content-Disposition", "attachment; filename=\"" + newFileName + "\"");
        } else {
            newFileName = URLEncoder.encode(fileName + ".png", StandardCharsets.UTF_8).replaceAll("\\+", "%20");
            response.setHeader("Content-Disposition", "attachment; filename=\"" + newFileName + "\"");
        }
        return response.getOutputStream();
    }

    private static QrConfig getQrConfig(Integer width, Integer height, Integer margin, Color foreColor, Color backColor, String imgPath, ErrorCorrectionLevel errorCorrectionLevel) {
        width = width == null ? 300 : width;
        height = height == null ? 300 : height;
        margin = margin == null ? 3 : margin;
        QrConfig config = new QrConfig(width, height);
        config.setMargin(margin);// 二维码与背景的边距
        if (foreColor != null)
            config.setForeColor(foreColor);// 颜色
        if (backColor != null)
            config.setBackColor(backColor);// 背景色
        if (!StrUtil.isBlank(imgPath))
            config.setImg(FileUtil.file(imgPath));// logo路径
        if (errorCorrectionLevel != null)
            config.setErrorCorrection(errorCorrectionLevel);
        return config;
    }

}
